using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;

public class Tree : MonoBehaviour
{
    public int[] treeNodeNumbers;

    public GameObject treePrefab;

    private BintryTree<TreeNode> tree;

    // Start is called before the first frame update
    void Start()
    {

    }

    public void InitTree()
    {
        int len = treeNodeNumbers.Length;
        tree = new BintryTree<TreeNode>(len);
        int raw = Mathf.FloorToInt(Mathf.Log(len, 2)) + 1;
        transform.localScale = Vector3.one * (1.0f / raw);
        float disChilds = (Mathf.Pow(2, raw - 1) - 1) * 50;
        for (int i = 0; i < len; i++)
        {
            var obj = Instantiate(treePrefab, transform);
            obj.SetActive(false);
            var td = obj.GetComponent<TreeNode>();
            td.id = i;
            tree.Add(td);
        }
        tree.FirstTraversal((index) =>
        {
            var idRaw = Mathf.FloorToInt(Mathf.Log(index + 1, 2)) + 1;
            if (index == 0)
            {
                idRaw = 1;
            }
            var left = (index + 1) * 2 - 1;
            var right = (index + 1) * 2;
            if (len > left)
            {
                tree.Data[index].leftNode = tree.Data[left];
                tree.Data[left].transform.parent = tree.Data[index].transform;

            }
            if (len > right)
            {
                tree.Data[index].rightNode = tree.Data[right];
                tree.Data[right].transform.parent = tree.Data[index].transform;

            }
            tree.Data[index].childSize = 1;
            tree.Data[index].value = treeNodeNumbers[index];
            tree.Data[index].disChilds = disChilds / Mathf.Pow(2, idRaw);
            tree.Data[index].gameObject.SetActive(true);
            tree.Data[index].Init();
        });
    }
    public LineRenderer line;
    public Vector3[] linePos;
    private WaitForSeconds wait = new WaitForSeconds(0.02f);
    public void FirstTraversal()
    {
        line.positionCount = 0;
        line.positionCount = treeNodeNumbers.Length;
        linePos = new Vector3[treeNodeNumbers.Length];
        int i = 0;
        tree.FirstTraversal((index) =>
       {
           var dir = tree.Data[index].transform.position;
           dir.z -= 1;
           linePos[i] = dir;
           i++;
       });
        StartCoroutine(ILineRd(linePos, 0.5f));
    }

    public void MilldeTraversal()
    {
        line.positionCount = 0;
        line.positionCount = treeNodeNumbers.Length;
        linePos = new Vector3[treeNodeNumbers.Length];

        int i = 0;
        tree.ModelTraversal((index) =>
       {
           var dir = tree.Data[index].transform.position;
           dir.z -= 1;
           linePos[i] = dir;

           i++;
       });
        StartCoroutine(ILineRd(linePos, 0.5f));

    }
    public void EndTraversal()
    {
        line.positionCount = 0;
        line.positionCount = treeNodeNumbers.Length;
        linePos = new Vector3[treeNodeNumbers.Length];

        int i = 0;
        tree.EndTraversal((index) =>
       {
           var dir = tree.Data[index].transform.position;
           dir.z -= 1;
           linePos[i] = dir;

           i++;
       });
        StartCoroutine(ILineRd(linePos, 0.5f));

    }

    public void ClearTreeNode()
    {
        if (tree == null || tree.Data == null) return;
        for (int i = 0; i < tree.Data.Length; i++)
        {
            Destroy(tree.Data[i].gameObject);
        }
    }
    IEnumerator ILineRd(Vector3[] pos, float iter)
    {
        int index = 1;
        float t = 0;
        line.SetPosition(0, pos[0]);
        while (index < pos.Length)
        {
            if (index > line.positionCount)
            {
                index = pos.Length;
            }
            t += 0.02f;
            yield return wait;
            line.SetPosition(index, Vector3.Lerp(pos[index - 1], pos[index], t / iter));
            if (t >= iter)
            {
                index++;
                t = 0;
            }
        }
    }

    public void OpenLineRender()
    {
        foreach (var item in tree.Data)
        {
            item.LineLeft();
            item.LineRight();
        }
    }

    public void ClearILine()
    {
        line.positionCount = 0;
    }
    public void ClearNodeLine()
    {
        foreach (var item in tree.Data)
        {
            item.ClearLine();
        }
    }
    public bool isOpenNodeLine;
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            ClearTreeNode();
            InitTree();
        }
        if (Input.GetKeyDown(KeyCode.Q))
        {
            FirstTraversal();
        }
        if (Input.GetKeyDown(KeyCode.W))
        {
            MilldeTraversal();
        }
        if (Input.GetKeyDown(KeyCode.E))
        {
            EndTraversal();
        }
        if (Input.GetKeyDown(KeyCode.C))
        {
            ClearILine();
        }
        if (Input.GetKeyDown(KeyCode.A))
        {
            if (isOpenNodeLine)
            {
                ClearNodeLine();
            }
            else
            {
                OpenLineRender();
            }
            isOpenNodeLine = isOpenNodeLine == false;

        }
    }
}
